package com.xx.doublexchat.common.weixin.service.impl;

import cn.hutool.core.util.StrUtil;
import com.xx.doublexchat.common.user.adapter.UserAdapter;
import com.xx.doublexchat.common.user.dao.UserDao;
import com.xx.doublexchat.common.user.domain.entity.User;
import com.xx.doublexchat.common.user.service.IUserService;
import com.xx.doublexchat.common.websocket.service.WebSocketService;
import com.xx.doublexchat.common.weixin.adapter.TextBuilder;
import com.xx.doublexchat.common.weixin.service.WXMsgService;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.URLEncoder;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Service
@Slf4j
public class WXMsgServiceImpl implements WXMsgService {
    // openId和登录code的关系map
    private static final ConcurrentHashMap<String,Integer> WAIT_AUTHORIZE_MAP = new ConcurrentHashMap<>();

    public static final String GRSCENE = "grscene_";
    @Value("${doublex-chat.wx.callback}")
    private String callBackUrl;

    @Resource
    private UserDao userDao;

    @Resource
    private IUserService userService;

    @Resource
    private WebSocketService webSocketService;

    public static final String URL = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=%s&redirect_uri=%s&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";

    @Override
    public WxMpXmlOutMessage scan(WxMpService wxMpService, WxMpXmlMessage wxMpXmlMessage) {
        // openId 微信用户Id
        String openId = wxMpXmlMessage.getFromUser();
        // 事件码
        Integer sceneId = getSceneId(wxMpXmlMessage);
        if (Objects.isNull(sceneId)) {
            return null;
        }
        User user = userDao.getByOpenId(openId);
        // 是否注册
        boolean registered = Objects.nonNull(user);
        // 是否授权
        boolean authorized = registered && StrUtil.isNotBlank(user.getAvatar());

        if (registered && authorized) {
            // 登录成功逻辑 通过code给前端channel推送消息
            webSocketService.scanLoginSuccess(sceneId,user.getId());
            return null;
        }

        if (!registered) {
            //进行注册逻辑
            User insertUser = UserAdapter.buildUser(openId);
            Long userId = userService.register(insertUser);
        }

        // 推送链接让用户授权------授权状态
        //将openid和sceneId存入关系map中
        WAIT_AUTHORIZE_MAP.put(openId,sceneId);
        webSocketService.waitAuthorize(sceneId);
        String authorUrl = String.format(URL, wxMpService.getWxMpConfigStorage().getAppId(), URLEncoder.encode(callBackUrl + "/wx/portal/public/callBackTest"));
        return TextBuilder.build("请点击登录：<a href=\"" + authorUrl + "\">登录</a>", wxMpXmlMessage);
    }

    /**
     * 用户授权更新用户信息
      * @param userInfo
     */
    @Override
    public void authorize(WxOAuth2UserInfo userInfo) {
        String openId = userInfo.getOpenid();
        User user = userDao.getByOpenId(openId);
        // 更新用户信息
        if (StrUtil.isBlank(user.getAvatar())) {
            fillUserInfo(user,userInfo);
        }
        // 通过sceneId找到用户channel，进行登录
        Integer sceneId = WAIT_AUTHORIZE_MAP.remove(openId);
        webSocketService.scanLoginSuccess(sceneId,user.getId());
    }

    /**
     * 填充用户信息
     * @param user
     * @param userInfo
     */
    private void fillUserInfo(User user, WxOAuth2UserInfo userInfo) {
        User updateUser = UserAdapter.buildUserAuthorizeUser(user, userInfo);
        //TODO 自定义额外逻辑
        userDao.updateById(updateUser);
    }

    /**
     * 获取事件码ID
     * @param wxMpXmlMessage
     * @return
     */
    private Integer getSceneId(WxMpXmlMessage wxMpXmlMessage) {
        try {
            String eventKey = wxMpXmlMessage.getEventKey();
            // 微信的事件码可能会带有grscene_
            String sceneId = eventKey.replace(GRSCENE, "");
            return Integer.parseInt(sceneId);
        } catch (Exception e) {
            log.error("getEvenKey error eventKey:{}", wxMpXmlMessage.getEventKey(), e);
            return null;
        }
    }
}
